﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpPcap;
using SharpPcap.LibPcap;
using System.Net.NetworkInformation;


namespace Derrick.AttackTest
{
    public class SpoofService
    {

        private SpoofEventArgs _spoofEventArgs = new SpoofEventArgs();
        private static ICaptureDevice _device = null;


        public event EventHandler<SpoofEventArgs> SpoofEvent;

        public static string SourceHardwareAddress { get; set; }
        public static string DestinationHardwareAddress { get; set; }
        public static string SourceIpAddress { get; set; }
        public static string DestinationIpAddress { get; set; }
        public static ushort SourcePort { get; set; }
        public static ushort DestinationPort { get; set; }

        public void RaiseSpoofEvent(SpoofEventArgs args)
        {
            if (null != SpoofEvent)
            {
                SpoofEvent(this, args);
            }
        }

        public SpoofService()
        {


        }

        public void StartSpoofing()
        {
            //Set Parameters:
            SourceIpAddress = SharedStorage.Instance.PhonyIpAddress;
            DestinationIpAddress = SharedStorage.Instance.DestinationIpAddress;
            SourcePort = SharedStorage.Instance.SourcePort;
            DestinationPort = SharedStorage.Instance.DestinationPort;
            SourceHardwareAddress = SharedStorage.Instance.SourceHardwareAddress;
            DestinationHardwareAddress = SharedStorage.Instance.DestinationHardwareAddress;

            // Print SharpPcap version
            string ver = SharpPcap.Version.VersionString;
            //Console.WriteLine("SharpPcap {0}, Example12.PacketManipulation.cs", ver);
            _spoofEventArgs.Message = "SharpPcap " + ver + ", Example12.PacketManipulation.cs";
            _spoofEventArgs.EventTime = DateTime.Now;
            //Console.WriteLine();
            RaiseSpoofEvent(_spoofEventArgs);

            // Retrieve the device list
            var devices = CaptureDeviceList.Instance;

            // If no devices were found print an error
            if (devices.Count < 1)
            {
                //Console.WriteLine("No devices were found on this machine");
                _spoofEventArgs.Message = "No devices were found on this machine";
                _spoofEventArgs.EventTime = DateTime.Now;
                RaiseSpoofEvent(_spoofEventArgs);
                return;
            }

            //Console.WriteLine("The following devices are available on this machine:");
            //Console.WriteLine("----------------------------------------------------");
            //Console.WriteLine();

            int i = 0;
            SharedStorage.Instance.DevicesForCapturing.Clear();

            // Print out the available devices
            foreach (var dev in devices)
            {
                //Console.WriteLine("{0}) {1}", i, dev.Description);
                SharedStorage.Instance.AddDeviceForCapturing(i, dev.Description);
                i++;
            }
            //Console.WriteLine("{0}) {1}", i, "Read packets from offline pcap file");

            //Console.WriteLine();
            //Console.Write("-- Please choose a device to capture: ");
            //var choice = int.Parse(Console.ReadLine());

            SelectDevice selectDeviceWindow = new SelectDevice();
            selectDeviceWindow.ShowDialog();

            //if (choice == i)
            //{
            //    Console.Write("-- Please enter an input capture file name: ");
            //    string capFile = Console.ReadLine();
            //    device = new CaptureFileReaderDevice(capFile);
            //}
            //else
            //{
            //    device = devices[choice];
            //}

            int choice = 0;
            foreach (schemaAttack.DevicesForCapturingRow deviceRow in SharedStorage.Instance.DevicesForCapturing)
            {
                if (deviceRow.Selected)
                {
                    choice = deviceRow.Device_ID;
                    break;
                }
            }

            _device = devices[choice];


            //Register our handler function to the 'packet arrival' event
            _device.OnPacketArrival +=
                new PacketArrivalEventHandler(device_OnPacketArrival);

            // Open the device for capturing
            _device.Open();

            //Console.WriteLine();
            //Console.WriteLine
            //    ("-- Listening on {0}, hit 'Ctrl-C' to exit...",
            //    device.Description);
            _spoofEventArgs.EventTime = DateTime.Now;
            _spoofEventArgs.Message = "-- Listening on " + _device.Description + "...";
            RaiseSpoofEvent(_spoofEventArgs);

            // Start capture 'INFINTE' number of packets
            _device.Capture();

            // Close the pcap device
            // (Note: this line will never be called since
            //  we're capturing infinite number of packets
            _device.Close();

        }

        private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            var packet = PacketDotNet.Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
            if (packet is PacketDotNet.EthernetPacket)
            {
                var eth = ((PacketDotNet.EthernetPacket)packet);
                //Console.WriteLine("Original Eth packet: " + eth.ToString());
                SharedStorage.Instance.AddDebugInfo("Spoof", "Original Eth packet: " + eth.ToString(), String.Empty, String.Empty);

                //Manipulate ethernet parameters
                if (String.IsNullOrEmpty(SourceHardwareAddress))
                {
                    eth.SourceHwAddress = PhysicalAddress.Parse("00-11-22-33-44-55");
                }
                else
                {
                    eth.SourceHwAddress = PhysicalAddress.Parse(SourceHardwareAddress);
                }
                if (String.IsNullOrEmpty(DestinationHardwareAddress))
                {
                    eth.DestinationHwAddress = PhysicalAddress.Parse("00-99-88-77-66-55");
                }
                else
                {
                    eth.DestinationHwAddress = PhysicalAddress.Parse(DestinationHardwareAddress);
                }

                var ip = PacketDotNet.IpPacket.GetEncapsulated(packet);

                

                if (ip != null)
                {
                    //Console.WriteLine("Original IP packet: " + ip.ToString());
                    SharedStorage.Instance.AddDebugInfo("Spoof", "Original IP packet: " + ip.ToString(), SourceIpAddress, DestinationIpAddress);

                    //manipulate IP parameters
                    if (String.IsNullOrEmpty(SourceIpAddress))
                    {
                        ip.SourceAddress = System.Net.IPAddress.Parse("1.2.3.4");
                    }
                    else
                    {
                        ip.SourceAddress = System.Net.IPAddress.Parse(SourceIpAddress);
                    }
                    if (String.IsNullOrEmpty(DestinationIpAddress))
                    {
                        ip.DestinationAddress = System.Net.IPAddress.Parse("44.33.22.11");
                    }
                    else
                    {
                        ip.DestinationAddress = System.Net.IPAddress.Parse(DestinationIpAddress);
                    }
                    ip.TimeToLive = 11;

                    var tcp = PacketDotNet.TcpPacket.GetEncapsulated(packet);
                    if (tcp != null)
                    {
                        //Console.WriteLine("Original TCP packet: " + tcp.ToString());
                        SharedStorage.Instance.AddDebugInfo("Spoof", "Original TCP packet: " + tcp.ToString(), SourceIpAddress, DestinationIpAddress);

                        //manipulate TCP parameters
                        tcp.SourcePort = SourcePort;
                        tcp.DestinationPort = DestinationPort;
                        tcp.Syn = !tcp.Syn;
                        tcp.Fin = !tcp.Fin;
                        tcp.Ack = !tcp.Ack;
                        tcp.WindowSize = 500;
                        tcp.AcknowledgmentNumber = 800;
                        tcp.SequenceNumber = 800;
                    }

                    var udp = PacketDotNet.UdpPacket.GetEncapsulated(packet);
                    if (udp != null)
                    {
                        //Console.WriteLine("Original UDP packet: " + udp.ToString());
                        SharedStorage.Instance.AddDebugInfo("Spoof", "Original UDP packet: " + udp.ToString(), SourceIpAddress, DestinationIpAddress);

                        //manipulate UDP parameters
                        udp.SourcePort = SourcePort;
                        udp.DestinationPort = DestinationPort;
                    }
                }

                //Console.WriteLine("Manipulated Eth packet: " + eth.ToString());
                SharedStorage.Instance.AddDebugInfo("Spoof", "Manipulated Eth packet: " + eth.ToString(), SourceIpAddress, DestinationIpAddress);
            }
        }

        public void StopSpoofing()
        {
            if (_device != null)
            {
                _device.Close();
            }
        }

    }
}
